package ihm.panel.site;

import ihm.applet.KrakenApplet;
import ihm.panel.PanelInterface;
import ihm.panel.camera.CameraPanel;

import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;

import network.KrakenClient;
import network.messages.KrakenClientMsg;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;

import tools.AppletConstant;

import bdd.sql.server.bean.Encryption;
import bdd.sql.server.bean.ServerCentral;
import bdd.sql.server.bean.ServerSite;
import bdd.sql.server.bean.ServerWeb;

/**
 * Affiche les algorithmes selectionnés.
 * @author Guillaume Pocas & Jean-Fraçois Augé
 */
public class CipherPanel extends JPanel implements PanelInterface, ActionListener {
	
	private static final long serialVersionUID = 1L;
	private KrakenApplet applet;
	private CameraPanel camera;

	private JLabel title_jl;
	private JLabel cipher_jl;
	private JComboBox<String> ciphers_jcb;
	private JButton dhKey_jb, key_jb;
	
	private List<Encryption> encrypts;
	
	private static final int BUTTON_INSETS = 3;
	
	/**
	 * Constructeur.
	 * @param applet
	 * @param camera
	 */
	public CipherPanel(KrakenApplet applet, CameraPanel camera) {
		this.applet = applet;
		this.camera = camera;
		updateTableInfo();
		initPanel();
	}
	
	@Override
	public void initPanel() {
		GridBagConstraints c = new GridBagConstraints();
		
		title_jl = new JLabel("<html><u>Configuration du serveur de site</u></html>");
		title_jl.setFont(new Font("Tahoma", Font.PLAIN, 30));
		
		String[] encryptNames = new String[encrypts.size()];
		for(int i = 0; i<encrypts.size(); i++)
			encryptNames[i] = encrypts.get(i).getEncrypt_name();
		
		ciphers_jcb = new JComboBox<String>(encryptNames);
		ciphers_jcb.setPreferredSize(AppletConstant.FIELD_SIZE);
		
		ciphers_jcb.addActionListener(this);
		
		cipher_jl = new JLabel("Selectionner : ");
		
		dhKey_jb = new JButton("Générer clé DH");
		dhKey_jb.addActionListener(this);
		
		key_jb = new JButton("Générer clé");
		key_jb.addActionListener(this);
		
		setLayout(new GridBagLayout());
		c.insets = new Insets(BUTTON_INSETS, BUTTON_INSETS, BUTTON_INSETS, BUTTON_INSETS); // marges pour chaque objets
		
		c.gridx = 0;								// position en x
		c.gridy = 0;								// position en y
		c.gridwidth = GridBagConstraints.REMAINDER;	// largeur de l'object en nombre de case, ici le reste de la ligne
		c.anchor = GridBagConstraints.WEST;			// l'ancrage de l'object
		c.fill = GridBagConstraints.NONE;			// est ce que l'object prend toute la case?
		add(title_jl, c);
		
		c.gridx = 0;
		c.gridy = 2;
		c.gridwidth = 1;
		c.anchor = GridBagConstraints.WEST;
		c.fill = GridBagConstraints.NONE;
		add(cipher_jl, c);
		
		c.gridx = 1;
		c.gridy = 2;
		c.gridwidth = GridBagConstraints.REMAINDER;
		c.anchor = GridBagConstraints.EAST;
		c.fill = GridBagConstraints.HORIZONTAL;
		add(ciphers_jcb, c);
		
		c.gridx = 0;
		c.gridy = 3;
		c.gridwidth = 1;
		c.anchor = GridBagConstraints.WEST;
		c.fill = GridBagConstraints.NONE;
		add(dhKey_jb, c);
		
		c.gridx = 1;
		c.gridy = 3;
		c.gridwidth = GridBagConstraints.REMAINDER;
		c.anchor = GridBagConstraints.EAST;
		c.fill = GridBagConstraints.HORIZONTAL;
		add(key_jb, c);
	}
	
	/**
	 * Met à jour l'algorithme selectionné.
	 */
	public void setSelectedEncryption() {		
		String siteName = camera.getNodePanel().getCurrentSite().getSiteserv_name();
		Session session = applet.getSession();
		ServerSite site = (ServerSite) session.createCriteria(ServerSite.class).
				add(Restrictions.like("siteserv_name", siteName)).list().get(0);
		
		if(!(site.getEncryption() == null))
			ciphers_jcb.getModel().setSelectedItem(site.getEncryption().getEncrypt_name());
		else
			ciphers_jcb.getModel().setSelectedItem("");

		session.close();
	}
	
	@SuppressWarnings("unchecked")
	public void updateTableInfo() {
		Session session = applet.getSession();
		encrypts = session.createCriteria(Encryption.class).list();
		
		if(ciphers_jcb != null && encrypts != null) {
			remove(ciphers_jcb);
			
			String[] encryptNames = new String[encrypts.size()];
			for(int i = 0; i<encrypts.size(); i++)
				encryptNames[i] = encrypts.get(i).getEncrypt_name();

			ciphers_jcb = new JComboBox<String>(encryptNames);
			ciphers_jcb.setPreferredSize(AppletConstant.FIELD_SIZE);
			ciphers_jcb.addActionListener(this);
			
			GridBagConstraints c = new GridBagConstraints();
			c.insets = new Insets(BUTTON_INSETS, BUTTON_INSETS, BUTTON_INSETS, BUTTON_INSETS);
			c.gridx = 1;
			c.gridy = 2;
			c.gridwidth = GridBagConstraints.REMAINDER;
			c.anchor = GridBagConstraints.EAST;
			c.fill = GridBagConstraints.HORIZONTAL;
			add(ciphers_jcb, c);
			
			revalidate();
		}
		
		session.close();
		System.out.println("refresh cipher panel2");
	}
	
	public void createKeyEncryption(String algoName, String ip_web, String ip_global, String ip_local, String global_name){
		String algo = algoName;
		String answer = "";
		
		if(!algo.equals("")) {
			//String siteName = camera.getNodePanel().getCurrentSite().getSiteserv_name();
			ArrayList<String> msg = new ArrayList<String>();
			
			msg.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
			msg.add(KrakenClientMsg.GENERATE_KEY.makeCommand(" "+algoName,
					" "+ip_global,
					" "+ip_local,
					" "+global_name)); 
			msg.add(KrakenClientMsg.END_CLIENT.toString());
			
			KrakenClient krakenClient = new KrakenClient(msg, ip_web);
			krakenClient.connect();
			krakenClient.communicate();
			
			answer = krakenClient.getFinalAnswer();
			
			if(answer.equalsIgnoreCase("END_SERVER")){
				System.out.println("Transfert TCP réussi");
			}
			else{
				//TODO cas d'erreur
				System.out.println("Erreur Transfert TCP : "+answer);
			}
		}
	}
	
	public void setEncrytion(ServerSite site, String algoName) {
		String answer = "";
		ServerCentral global = site.getGlobalServer();
		String siteName = site.getSiteserv_name();
		ArrayList<String> msg = new ArrayList<String>();
		
		msg.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
		msg.add(KrakenClientMsg.ENCRYPTION_PARAMETER.makeCommand(" "+algoName,
				" "+global.getServCentr_ip(),
				" "+site.getSiteserv_ip())); 
		msg.add(KrakenClientMsg.END_CLIENT.toString());
		
		Session session = applet.getSession();
		@SuppressWarnings("unchecked")
		List<ServerWeb> resultats = session.createCriteria(ServerWeb.class).add(Restrictions.eq("webserv_name", "web1")).list();
		String ip = "";
		if(resultats.size() == 1){
			System.out.println("Serveur Web détecté");
			ip = resultats.get(0).getWebserv_ip();
		}
		else	ip = "10.4.101.189"; //192.168.2.51
		//ip = ""; //test local
		
		KrakenClient krakenClient = new KrakenClient(msg, ip);
		krakenClient.connect();
		krakenClient.communicate();
		
		answer = krakenClient.getFinalAnswer();
		
		if(answer.equalsIgnoreCase("END_SERVER")){
			System.out.println("Transfert TCP réussi");
			// change data base
			Encryption encrypt = (Encryption) session.createCriteria(Encryption.class).
					add(Restrictions.like("encrypt_name", algoName)).list().get(0);
			ServerSite site2 = (ServerSite) session.createCriteria(ServerSite.class).
					add(Restrictions.like("siteserv_name", siteName)).list().get(0);
			
			System.out.println("Applying "+encrypt.getEncrypt_name()+" to "+site2.getSiteserv_name());
			
			Transaction tx = session.beginTransaction();
			site2.setEncryption(encrypt);
			session.save(site2);
			tx.commit();
			
			this.createKeyEncryption(algoName,ip,global.getServCentr_ip(),site.getSiteserv_ip(), global.getServCentr_name());
			
			session.close();
		}
		else{
			//TODO cas d'erreur
			System.out.println("Erreur Transfert TCP : "+answer);
		}
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		if(e.getSource().equals(dhKey_jb)) {
			// créer un nouveau client pour propager une nouvelle clé dh
			ServerSite site = camera.getNodePanel().getCurrentSite();
			ServerCentral global = site.getGlobalServer();
			String global_name = global.getServCentr_name();
			
			ArrayList<String> msg = new ArrayList<String>();
			msg.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
			msg.add(KrakenClientMsg.DH_KEY.makeCommand(" "+global.getServCentr_ip()," "+site.getSiteserv_ip(), " "+global_name));
			msg.add(KrakenClientMsg.END_CLIENT.toString());
			
			Session session = applet.getSession();
			@SuppressWarnings("unchecked")
			List<ServerWeb> resultats = session.createCriteria(ServerWeb.class).add(Restrictions.eq("webserv_name", "web1")).list();
			String ip = "";
			if(resultats.size() == 1) {
				System.out.println("Serveur Web détecté");
				ip = resultats.get(0).getWebserv_ip();
			}
			else
				ip = "10.4.101.189";
			//ip = ""; //test local
			
			KrakenClient krakenClient = new KrakenClient(msg, ip);
			krakenClient.connect();
			krakenClient.communicate();
			
			String answer = krakenClient.getFinalAnswer();
			
			if(answer.equalsIgnoreCase("END_SERVER"))
				System.out.println("Transfert TCP réussi");
			else
				System.out.println("Transfert TCP échoué");
		}
		else if(e.getSource().equals(key_jb)) {
			// on envoie une demande de création de clé avec l'algo sélectionné
			Session session = applet.getSession();
			@SuppressWarnings("unchecked")
			List<ServerWeb> resultats = session.createCriteria(ServerWeb.class).add(Restrictions.eq("webserv_name", "web1")).list();
			String ip = "";
			if(resultats.size() == 1){
				System.out.println("Serveur Web détecté");
				ip = resultats.get(0).getWebserv_ip();
			}
			else	ip = "10.4.101.189"; //192.168.2.51
			//ip = ""; //test local
			ServerSite site = camera.getNodePanel().getCurrentSite();
			this.createKeyEncryption((String) ciphers_jcb.getSelectedItem(),ip,site.getGlobalServer().getServCentr_ip(),site.getSiteserv_ip(), site.getGlobalServer().getServCentr_name());
			session.close();
		}
		else {
			String algoName = (String) ciphers_jcb.getSelectedItem();
			ServerSite site = camera.getNodePanel().getCurrentSite();
			
			if(!ciphers_jcb.getSelectedItem().equals("")) {
				if(algoName != null) {
					//JDialogWait wait = new JDialogWait("Veuillez patienter...");
					
					//wait.run();
					//wait.display();
					if(site.getEncryption() == null) {
						this.setEncrytion(site, algoName);
					}
					else if(!site.getEncryption().getEncrypt_name().equals(algoName)) {
						this.setEncrytion(site, algoName);
					}
					//wait.close();
				}
			}
			
		}
	}
	
}
